package com.fudan.es.service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.elasticsearch.action.admin.cluster.health.ClusterHealthRequest;
import org.elasticsearch.action.admin.cluster.health.ClusterHealthRequest.Level;
import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse;
import org.elasticsearch.action.fieldcaps.FieldCapabilities;
import org.elasticsearch.action.fieldcaps.FieldCapabilitiesRequest;
import org.elasticsearch.action.fieldcaps.FieldCapabilitiesResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.GetMappingsRequest;
import org.elasticsearch.client.indices.GetMappingsResponse;
import org.elasticsearch.cluster.health.ClusterIndexHealth;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.fudan.es.EsClient;
import com.fudan.es.entity.FieldMeta;
import com.fudan.es.indices.IndexStatus;
import com.fudan.framework.utils.StringUtils;

@Service
public class IndexAdminService {

	@Autowired
	private EsClient esClient;

	public List<IndexStatus> indices(String dsId) {
		RestHighLevelClient client = esClient.getClient(dsId);
		List<IndexStatus> list = new ArrayList<>();
		try {
			ClusterHealthRequest request = new ClusterHealthRequest();
			request.level(Level.INDICES);
			ClusterHealthResponse response = client.cluster().health(request, RequestOptions.DEFAULT);
			Map<String, ClusterIndexHealth> indices = response.getIndices();
			Set<String> indicesSet = indices.keySet();
			for (String index : indicesSet) {
				list.add(IndexStatus.build(index, indices.get(index).getActiveShards(), indices.get(index).getStatus().name()));
			}
			return list;
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}

	public List<IndexStatus> indices(String dsId,String pattern) {
		RestHighLevelClient client = esClient.getClient(dsId);
		List<IndexStatus> list = new ArrayList<>();
		try {
			ClusterHealthRequest request = new ClusterHealthRequest();
			request.level(Level.INDICES);
			ClusterHealthResponse response = client.cluster().health(request, RequestOptions.DEFAULT);
			Map<String, ClusterIndexHealth> indices = response.getIndices();
			Set<String> indicesSet = indices.keySet();
			for (String index : indicesSet) {
				if(index.contains(pattern)) {
					list.add(IndexStatus.build(index, indices.get(index).getActiveShards(), indices.get(index).getStatus().name()));
				}
			}
			return list;
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}

	public Map<String,Object> getFieldMapping(Integer dwId,String index) throws IOException {
		GetMappingsResponse mappingResponse = esClient.getClientByDataWareId(dwId).indices().getMapping(new GetMappingsRequest().indices(index), RequestOptions.DEFAULT);
		return mappingResponse.mappings().get(index).getSourceAsMap();
	}

	public void parseProperties(List<FieldMeta> fieldList,FieldMeta parent,Map<String,Object> map) {
		if(map == null) return;
		Map<String,Object> properties = (Map<String, Object>) map.get("properties");
		if(properties!=null) {
			Set<String> fieldNames = properties.keySet();
			for (String fieldName : fieldNames) {
				FieldMeta meta = new FieldMeta(false,false);
				FieldMeta keyMeta = null;
				Map<String,Object> fieldInfo = (Map<String, Object>) properties.get(fieldName);
				String type = (String) fieldInfo.get("type");
				if(type == null) {
					type = "object";
				}
				meta.setType(type);
				Map<String,Object> fields = (Map<String, Object>) fieldInfo.get("fields");
				if(fields!=null) {
					Map<String,Object> keyword = (Map<String, Object>) fields.get("keyword");
					if(keyword!=null) {
						String keyType = (String) keyword.get("type");
						if("keyword".equals(keyType)) {
							keyMeta = new FieldMeta(false,false);
							keyMeta.setType(keyType);
						}
					}
				}
				if(parent != null) {
					if("nested".equals(parent.getType())) {
						meta.nested(true).nestedPath(parent.getName());
						if(keyMeta != null) {
							keyMeta.nested(true).nestedPath(parent.getName());
						}
					}
					meta.setName(StringUtils.concat(parent.getName(),".",fieldName));
					meta.setAlias(meta.getName());
					if(keyMeta != null) {
						keyMeta.setName(StringUtils.concat(parent.getName(),".",fieldName,".keyword"));
						keyMeta.setAlias(keyMeta.getName());
					}
				}else {
					meta.setName(fieldName);
					meta.setAlias(meta.getName());
					if(keyMeta != null) {
						keyMeta.setName(StringUtils.concat(fieldName,".keyword"));
						keyMeta.setAlias(keyMeta.getName());
					}
				}
				fieldList.add(meta);
				if(keyMeta!=null) {
					fieldList.add(keyMeta);
				}
				parseProperties(fieldList,meta,fieldInfo);
			}
		}
	}

	public void fillAbility(List<FieldMeta> fieldList,String index,Integer dsId) throws IOException {
		RestHighLevelClient client = esClient.getClient(dsId);
		FieldCapabilitiesResponse fieldCaps = client.fieldCaps(new FieldCapabilitiesRequest().indices(index).fields("*"), RequestOptions.DEFAULT);
		for (FieldMeta fieldMeta : fieldList) {
			Map<String, FieldCapabilities> fieldCap = fieldCaps.getField(fieldMeta.getName());
			if(fieldCap == null) {
				continue;
			}
			boolean searchable = fieldCap.get(fieldMeta.getType()).isSearchable();
			boolean aggregatable = fieldCap.get(fieldMeta.getType()).isAggregatable();
			fieldMeta.setSearchable(searchable);
			fieldMeta.setAggregatable(aggregatable);
		}
	}

}
